package hotel.controller;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;

import hotel.dao.HotelDao;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.geometry.Bounds;
import javafx.scene.chart.PieChart;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Label;
import javafx.scene.text.Text;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.chart.BarChart;

import javafx.scene.chart.NumberAxis;

public class StatisticsController {
	@FXML
	private PieChart pieChart;
	@FXML
	private BarChart<String, Number> barChart;
	@FXML
	private CategoryAxis x;
	@FXML
	private NumberAxis y;
	@FXML
	private Label reserveCountLbl;
	@FXML
	private Label reservePercentLbl;
	@FXML
	private Label basicIncomeLbl;
	@FXML
	private Label rentCountLbl;
	@FXML
	private Label orderCountLbl;
	@FXML
	private Label otherIncomeLbl;
	@FXML
	private Label rentPercentLbl;
	@FXML
	private Label orderPercentLbl;
	
	@FXML
	public void initialize() {
		showPieChartData();
		showBarChartData();
		showMonthlyStatistics();
	}
	
	protected void showPieChartData() {
		LocalDateTime end = LocalDateTime.now();
		LocalTime time = LocalTime.of(0, 0, 0);
		LocalDateTime start = end.minusWeeks(1).with(time); // 减一周再重置时间
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		String startTime = start.format(formatter);
		String endTime = end.format(formatter);
		
		int reserve = HotelDao.countReserveInfo(startTime, endTime);
		int rent = HotelDao.countRentInfo(startTime, endTime);
		int leave = HotelDao.countOrderInfo(startTime, endTime);
		ObservableList<PieChart.Data> pieChartData =
                FXCollections.observableArrayList(
                new PieChart.Data("预定", reserve),
                new PieChart.Data("入住", rent),
                new PieChart.Data("离开", leave));
		
		pieChartData.forEach(data -> data.nameProperty().bind(
				Bindings.concat(data.getName(), " ", (int)(data.pieValueProperty().get()), " 人")));
        pieChart.getData().addAll(pieChartData);
	}
	
	protected void showBarChartData() {
		Series<String, Number> reserveSet = new XYChart.Series<>();
		Series<String, Number> rentSet = new XYChart.Series<>();
		Series<String, Number> leaveSet = new XYChart.Series<>();
		
		reserveSet.setName("预定");
		rentSet.setName("入住");
		leaveSet.setName("离开");
		
		LocalDateTime now = LocalDateTime.now();
		LocalTime minTime= LocalTime.of(0, 0, 0);
		LocalTime maxTime = LocalTime.of(23, 59, 59);
		LocalDateTime start, end;
		String startTime, endTime, title;
		int reserve, rent, leave;
		DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		DateTimeFormatter df = DateTimeFormatter.ofPattern("M.d");
		
		for(int i = 6; i >= 0; i--) {
			start = now.minusDays(i).with(minTime);
			end = now.minusDays(i).with(maxTime);
			startTime = start.format(dtf);
			endTime = end.format(dtf);
			reserve = HotelDao.countReserveInfo(startTime, endTime);
			rent = HotelDao.countRentInfo(startTime, endTime);
			leave = HotelDao.countOrderInfo(startTime, endTime);
			title = start.format(df);
			final XYChart.Data<String, Number> reserveData = new Data<>(title, reserve);
			final XYChart.Data<String, Number> rentData = new Data<String, Number>(title, rent);
			final XYChart.Data<String, Number> leaveData = new Data<String, Number>(title, leave);
			setChangedListener(reserveData);
			setChangedListener(rentData);
			setChangedListener(leaveData);
			reserveSet.getData().add(reserveData);
			rentSet.getData().add(rentData);
			leaveSet.getData().add(leaveData);
		}
		barChart.getData().add(reserveSet);
		barChart.getData().add(rentSet);
		barChart.getData().add(leaveSet);
	}
	
	private void showMonthlyStatistics() {
		// TODO
		LocalDateTime now = LocalDateTime.now();
		LocalTime minTime= LocalTime.of(0, 0, 0);
		LocalTime maxTime = LocalTime.of(23, 59, 59);
		LocalDateTime start, end;
		String startTime, endTime;
		DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		start = now.with(TemporalAdjusters.firstDayOfMonth()).with(minTime); 	// 本月第一天
		end = now.with(TemporalAdjusters.lastDayOfMonth()).with(maxTime);		// 本月最后一天
		startTime = start.format(dtf);
		endTime = end.format(dtf);
		int reserve = HotelDao.countReserveInfo(startTime, endTime);
		int rent = HotelDao.countRentInfo(startTime, endTime);
		double realCharge = HotelDao.countRealCharge(startTime, endTime);
		double basicCharge = HotelDao.countBasicCharge(startTime, endTime);
		double otherCharge = HotelDao.countOtherCharge(startTime, endTime);
		reserveCountLbl.setText(String.valueOf(reserve));
		rentCountLbl.setText(String.valueOf(rent));
		orderCountLbl.setText(String.format("%.2f", realCharge));
		basicIncomeLbl.setText(String.format("%.2f", basicCharge));
		otherIncomeLbl.setText(String.format("%.2f", otherCharge));
		
		start = now.minusMonths(1).with(TemporalAdjusters.firstDayOfMonth()).with(minTime); 	// 上月第一天
		end = now.minusMinutes(1).with(TemporalAdjusters.lastDayOfMonth()).with(maxTime);		// 上月最后一天
		int preReserve = HotelDao.countReserveInfo(startTime, endTime);
		int preRent = HotelDao.countRentInfo(startTime, endTime);
		double preRealCharge = HotelDao.countRealCharge(startTime, endTime);
		double reservePercent = 0.0, rentPercent = 0.0, realChargePercent = 0.0;
		if(preReserve != 0) {
			reservePercent = (double)reserve / preReserve - 1.0;
		}
		if(preRent != 0) {
			rentPercent = (double)rent / preRent - 1.0;
		}
		if(preRealCharge != 0) {
			realChargePercent = (double)realCharge / preRealCharge - 1.0;
		}
		reservePercentLbl.setText(String.format("%.2f", reservePercent));
		rentPercentLbl.setText(String.format("%.2f", rentPercent));
		orderPercentLbl.setText(String.format("%.2f", realChargePercent));
		
		
	}
	
	private void setChangedListener(XYChart.Data<String, Number> data) {
		data.nodeProperty().addListener(new ChangeListener<Node>() {
			@Override
			public void changed(ObservableValue<? extends Node> ov, Node oldNode, final Node node) {
				if (node != null) {
					displayLabelForData(data);
				}
			}
		});
	}
	
	private void displayLabelForData(XYChart.Data<String, Number> data) {
		final Node node = data.getNode();
		final Text dataText = new Text(data.getYValue() + "");
		node.parentProperty().addListener(new ChangeListener<Parent>() {
			@Override
			public void changed(ObservableValue<? extends Parent> ov, Parent oldParent, Parent parent) {
				Group parentGroup = (Group) parent;
				parentGroup.getChildren().add(dataText);
			}
		});

		node.boundsInParentProperty().addListener(new ChangeListener<Bounds>() {
			@Override
			public void changed(ObservableValue<? extends Bounds> ov, Bounds oldBounds, Bounds bounds) {
				dataText.setLayoutX(Math.round(bounds.getMinX() + bounds.getWidth() / 2 - dataText.prefWidth(-1) / 2));
				dataText.setLayoutY(Math.round(bounds.getMinY() - dataText.prefHeight(-1) * 0.5));
			}
		});
	}
}
